数据结构之--双链表MyLinkedList
双链表的手动实现中考虑三个类的实现:
1、MyLinkedList类本身的实现,包含到两端的链、表的大小以及一些方法。
2、Node节点,它可能是一个私有的内部嵌套类,这个类,嵌套在MyLinkedList的内部,数据域:data,前驱指针prev和后继指针next,以及合适的构造方法
3、LinkedListIterator类,该类抽象了位置的概念,是一个实现了Iterator接口的私有类,它提供了next、hashNext和remove等方法。于我而言这个迭代器的实现感觉比较的有收获。主要注意要实现的是:我们在使用迭代器件,确保链表集合中的元素不会被用户越过迭代器而修改。都有过这样的经历:在java中执行迭代操作的过程中,比如:
1 LinkedList <Integet> kist = new LinkedList<Integer>(); 2 …… 3 Iterator<Integer> it = list.iterator(); 4 while(it.hasNext()) 5 { 6 syso(it.next); 7 list.remove(1);// 这里就会报错,这里面有一套保护机制,确保在使用迭代期间不允许使用集合和修改内部元素 8 it.remove(); // 这样同通过迭代器的修改是允许的 9 }
主要实现上面的保护机制。其实就是一个维护一个互斥变量的感觉。
具体的实现代码如下:
1 import java.util.Iterator; 2 3 import org.omg.CORBA.Any; 4 5 /** 6 * 自己手动实现一个 LinkedList 7 * 基于双向链表,其中,私有嵌套定义双向链表的节点 8 * 注意了我哥双向链表,n个元素记做1~n,标准库中记为0~n-1 9 * @author Administrator 10 * 11 */ 12 public class MyLinkedList <AnyType> implements Iterable<AnyType>{ 13 private int theSize; //双向链表中的元素个数 14 private int modCount; //这个标记为了配合Iterator实现修改的保护,这一点后面专做论述,凡是做了增删修改,这个标记均变化 15 private Node<AnyType> beginMarker; // 双向链表的开始标记 16 private Node<AnyType> endMarker; //双向链表的尾部标记 17 18 public MyLinkedList() 19 { 20 // 构造函数 先初始化双向聊表 调动 clear()函数 21 clear(); 22 } 23 public void clear() 24 {// 确保双向链表处于空的状态 ----> 我们使用一个辅助的头结点 25 // 头标记和尾标记 指向同一个 辅助头结点,和一个辅助的尾节点 26 beginMarker = new Node<AnyType>(null, null, null); 27 endMarker = new Node<AnyType>(null, beginMarker, null); 28 beginMarker.next = endMarker; 29 30 theSize = 0; 31 modCount ++; //zhege 32 } 33 34 // 获取元素的个数 35 public int size() 36 { 37 return theSize; 38 } 39 40 // 判断是否为空 41 public boolean isEmpty() 42 { 43 return theSize == 0; 44 } 45 46 47 /* 48 * 增删查改的操作 49 */ 50 // 默认把元素插入到尾部,其中调用插入到指定位置的函数 51 public boolean add(AnyType x) 52 { 53 add(size()+1, x); 54 return true; 55 } 56 // 把元素插入到指定位置,其中调用插入到指定元素之前 函数 57 public void add(int idx, AnyType x) 58 { 59 addBefore(getNode(idx), x); 60 } 61 // 重置某个节点的data值,并返回以前的 data值 62 public AnyType set(int idx, AnyType newVal) 63 { 64 if(idx <1 || idx >size()) 65 throw new RuntimeException(new Exception("下表越界")); 66 Node<AnyType> p = getNode(idx); 67 AnyType oldVal = p.data; 68 p.data = newVal; 69 return oldVal; 70 } 71 // 删除第idx个节点,调用remove(Node)函数,返回删除节点的data值 72 public AnyType remove(int idx) 73 { 74 if(idx <1 || idx >size()) 75 throw new RuntimeException(new Exception("下表越界")); 76 return remove(getNode(idx)); 77 } 78 79 80 81 /* 82 * 下面这些函数都是一些private的都是位别的一些函数服务的 83 */ 84 // 在p前面插入 x 元素 85 private void addBefore(Node<AnyType>p, AnyType x) 86 { 87 Node<AnyType> newNode = new Node<AnyType>(x, p.prev, p); 88 newNode.prev.next = newNode; 89 p.prev = newNode; 90 theSize ++; //添加进来一个新元素之后,别忘了元素个数++ 91 modCount ++; //无论增删 该标志 均++ 92 } 93 // 获取 idx处的 节点引用 94 private Node<AnyType> getNode(int idx) 95 { 96 if(idx < 1 || idx > size()+1)// 考虑在尾部插入的情况,如果取这个尾节点,其data = null 97 throw new RuntimeException(new Exception("索引越界")); 98 Node<AnyType> p = null; 99 if( idx <= size()/2) // 在前半边中找 100 { 101 p = beginMarker.next; 102 for( int i = 1; i < idx; i++) 103 p = p.next; 104 }else{ //在后半边中找 105 p = endMarker; 106 for(int i = size(); i >= idx; i--) 107 p = p.prev; 108 } 109 110 return p; 111 } 112 // 返回 删除某个节点,并返回这个节点的data值 113 private AnyType remove(Node<AnyType> p) 114 { 115 p.prev.next = p.next; 116 p.next.prev = p.prev; 117 theSize --; 118 modCount --; 119 return p.data; 120 } 121 122 123 /* 124 * 实现迭代器 125 */ 126 public Iterator<AnyType> iterator() 127 { 128 return new LinkedListIterator(); 129 } 130 //实现迭代器 131 private class LinkedListIterator implements Iterator<AnyType> 132 { 133 private Node<AnyType> current = beginMarker.next; //记住当前的位置,这和书序表中类似 134 private int expectedModCount = modCount; 135 private boolean okToRemove = false; 136 137 @Override 138 public boolean hasNext() { 139 // TODO Auto-generated method stub 140 return current!=endMarker; 141 } 142 143 @Override 144 public AnyType next() { 145 // 注意了 下面的 保护迭代期间 不允许 越过迭代器修改集合元素的 机制 是精髓 146 if(modCount != expectedModCount) 147 throw new RuntimeException(new Exception("您刚刚越过迭代器修改了集合元素")); 148 if(!hasNext()) 149 throw new RuntimeException(new Exception("已经没有元素了")); 150 151 AnyType nextItem = current.data; 152 current = current.next; 153 okToRemove = true; 154 return nextItem; 155 } 156 157 @Override 158 public void remove() { 159 // TODO Auto-generated method stub 160 if(modCount != expectedModCount) 161 throw new RuntimeException(new Exception("您刚刚越过迭代器修改了集合元素")); 162 if(!okToRemove) 163 throw new RuntimeException(new Exception("先next再删除")); 164 165 MyLinkedList.this.remove(current.prev); 166 okToRemove = false; // 与next()中的 okToRemove = false; 遥相呼应,以确保必须在next()之后才能remove 167 expectedModCount ++; 168 } 169 170 } 171 172 /* 173 * 私有嵌套类的形式,定义内部节点,节点里面没有访问双向链表中的内容,所以使用私有嵌套类可也 174 * 如果访问了外面类的属性或者方法就只能使用内部类,去除static关键字,内部类的使用主要是为了可以简写,见单链表中的介绍 175 */ 176 private static class Node<AnyType>{ 177 // 构造函数 178 public Node(AnyType d, Node<AnyType>p, Node<AnyType>n) { 179 data = d; prev = p; next = n; 180 } 181 182 public AnyType data; 183 public Node<AnyType> prev; 184 public Node<AnyType> next; 185 } 186 187 public static void main(String[] args) { 188 MyLinkedList<Integer> list= new MyLinkedList<Integer>(); 189 190 System.out.println("size : "+list.size()); 191 System.out.println("empty : "+list.isEmpty()); 192 list.add(1); 193 list.add(2); 194 list.add(4); 195 list.add(3, 3); 196 System.out.println("size : "+list.size()); 197 System.out.println("empty : "+list.isEmpty()); 198 199 list.set(4, 5); 200 201 System.out.println("dlete 4th elements :"+list.remove(4)); 202 System.out.println("size : "+list.size()); 203 } 204 }